home *** CD-ROM | disk | FTP | other *** search
/ Freelog 22 / freelog 22.iso / Prog / Djgpp / GPC2952B.ZIP / doc / gpc / demos / parserdemo.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2001-02-08  |  8.3 KB  |  323 lines

  1. {
  2. GPC demo program. A recursive descent parser for mathematical
  3. expressions using real or complex numbers.
  4.  
  5. The code is Extended Pascal, i.e., it can be compiled with the
  6. `--extended-pascal' option (but also in GPC's default mode).
  7.  
  8. Copyright (C) 1999-2001 Free Software Foundation, Inc.
  9.  
  10. Author: Frank Heckenbach <frank@pascal.gnu.de>
  11.  
  12. This program is free software; you can redistribute it and/or
  13. modify it under the terms of the GNU General Public License as
  14. published by the Free Software Foundation, version 2.
  15.  
  16. This program is distributed in the hope that it will be useful,
  17. but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. GNU General Public License for more details.
  20.  
  21. You should have received a copy of the GNU General Public License
  22. along with this program; see the file COPYING. If not, write to
  23. the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  24. Boston, MA 02111-1307, USA.
  25.  
  26. As a special exception, if you incorporate even large parts of the
  27. code of this demo program into another program with substantially
  28. different functionality, this does not cause the other program to
  29. be covered by the GNU General Public License. This exception does
  30. not however invalidate any other reasons why it might be covered
  31. by the GNU General Public License.
  32. }
  33.  
  34. program ParserDemo (Input, Output);
  35.  
  36. {
  37.   This parser understands the following grammar:
  38.  
  39.   CONSTANT = "e" | "pi" | "i" | POSITIVE_REAL_NUMBER | "$" POSITIVE_HEXADECIMAL_INTEGER_NUMBER
  40.   FUNCTION = "abs" | "sqrt" | "sin" | "cos" | "tan" | "arctan" | "exp" | "ln"
  41.   ATOM1 = "(" EXPR ")" | CONSTANT | ATOM1 "!"
  42.   ATOM = ATOM1 | FUNCTION ATOM
  43.   FACTOR = ATOM | FACTOR "^" ATOM
  44.   EXPR1 = FACTOR | EXPR1 "*" FACTOR | EXPR1 FACTOR (not starting with numeric constant) | EXPR1 "/" FACTOR
  45.   EXPR = EXPR1 | EXPR "+" EXPR1 | EXPR "-" EXPR1 | "-" EXPR1
  46. }
  47.  
  48. (*@@*)(*$W no-field-name-problem*)
  49.  
  50. procedure foo;(*@@fjf479.pas with `i!'*)
  51.  
  52. label 99;
  53.  
  54. { LoCase (even a version with NLS), Frac and Pi are built into GPC, but
  55.   deactivated when compiling with `--extended-pascal'. }
  56.  
  57. type
  58.   TString = String (4096);
  59.  
  60. const
  61.   Pi = 3.1415926535897932384626433832795028841971693993751;
  62.  
  63. function LoCase (ch : Char) : Char;
  64. begin
  65.   if ch in ['A' .. 'Z']
  66.     then LoCase := Succ (ch, Ord ('a') - Ord ('A'))
  67.     else LoCase := ch
  68. end;
  69.  
  70. function Frac (x : Real) : Real;
  71. var i : Real;
  72. begin
  73.   i := Round (x);
  74.   if Abs (i) > Abs (x) then
  75.     if i < 0
  76.       then i := i + 1
  77.       else i := i - 1;
  78.   Frac := x - i
  79. end;
  80.  
  81. function Real2Integer (x : Real; var i : Integer) : Boolean;
  82. const Delta = 1e-10;
  83. begin
  84.   if (Abs (x) <= MaxInt) and (Abs (x - Round (x)) <= Delta * Abs (x)) then
  85.     begin
  86.       i := Round (x);
  87.       Real2Integer := True
  88.     end
  89.   else
  90.     Real2Integer := False
  91. end;
  92.  
  93. function Real2String (x : Real) = s : TString;
  94. var i : Integer;
  95. begin
  96.   if Real2Integer (x, i) then
  97.     WriteStr (s, i)
  98.   else
  99.     WriteStr (s, x : 0 : 20)
  100. end;
  101.  
  102. function Complex2String (z : Complex) = s : TString;
  103. begin
  104.   s := Real2String (Re (z));
  105.   if Im (z) > 0 then s := s + ' +';
  106.   if Im (z) <> 0 then s := s + ' ' + Real2String (Im (z)) + ' * i'
  107. end;
  108.  
  109. procedure Skip;
  110. begin
  111.   while (Input^ = ' ') and not EOLn do Get (Input)
  112. end;
  113.  
  114. procedure Expect (ch : Char);
  115. begin
  116.   Skip;
  117.   if Input^ <> ch then
  118.     begin
  119.       Writeln ('`', ch, ''' expected');
  120.       goto 99
  121.     end;
  122.   Get (Input)
  123. end;
  124.  
  125. function Expr : Complex; forward;
  126.  
  127. function Atom : Complex;
  128. const
  129.   MaxFactorial = 170;
  130.   MaxFNames = 11;
  131. var
  132.   FNames : array [1 .. MaxFNames] of String (6) value
  133.     [1 : 'e'; 2 : 'pi'; 3 : 'i'; 4 : 'abs';
  134.      5 : 'sqrt'; 6 : 'sin'; 7 : 'cos'; 8 : 'tan';
  135.      9 : 'arctan'; 10 : 'exp'; 11 : 'ln'];
  136.   f : TString;
  137.   n, i : Integer;
  138.   r : Real;
  139.   z : Complex;
  140.   FactorialAllowed : Boolean;
  141. begin
  142.   Skip;
  143.   FactorialAllowed := True;
  144.   case LoCase (Input^) of
  145.     '0' .. '9',
  146.     '.'        : begin
  147.                    Read (r);
  148.                    z := r
  149.                  end;
  150.     '$'        : begin
  151.                    Read (i);
  152.                    z := i
  153.                  end;
  154.     '('        : begin
  155.                    Expect ('(');
  156.                    z := Expr;
  157.                    Expect (')')
  158.                  end;
  159.     'a' .. 'z' : begin
  160.                    f := '';
  161.                    while LoCase (Input^) in ['a' .. 'z'] do
  162.                      begin
  163.                        f := f + LoCase (Input^);
  164.                        Get (Input)
  165.                      end;
  166.                    i := MaxFNames;
  167.                    while (i > 0) and (f <> FNames [i]) do i := i - 1;
  168.                    if i = 0 then
  169.                      begin
  170.                        Writeln ('Unknown function `', f, '''');
  171.                        goto 99
  172.                      end;
  173.                    case i of
  174.                      1 : z := Exp (1);
  175.                      2 : z := Pi;
  176.                      3 : z := Cmplx (0, 1);
  177.                      otherwise
  178.                        FactorialAllowed := False;
  179.                        z := Atom;
  180.                        case i of
  181.                           4 : z := Abs (z);
  182.                           5 : z := Sqrt (z);
  183.                           6 : z := Sin (z);
  184.                           7 : z := Cos (z);
  185.                           8 : z := Sin (z) / Cos (z);
  186.                           9 : z := ArcTan (z);
  187.                          10 : z := Exp (z);
  188.                          11 : z := Ln (z);
  189.                        end
  190.                    end
  191.                  end;
  192.     otherwise
  193.       Writeln ('Parse error.');
  194.       goto 99
  195.   end;
  196.   if FactorialAllowed then
  197.     begin
  198.       Skip;
  199.       while Input^ = '!' do
  200.         begin
  201.           if (Im (z) = 0) and Real2Integer (Re (z), n) and (n >= 0) and (n <= MaxFactorial) then
  202.             begin
  203.               r := 1;
  204.               for i := 2 to n do r := i * r;
  205.               z := r
  206.             end
  207.           else
  208.             begin
  209.               Writeln ('Argument of `!'' must be an integer between 0 and ', MaxFactorial, '.');
  210.               goto 99
  211.             end;
  212.           Get (Input);
  213.           Skip
  214.         end
  215.     end;
  216.   Atom := z
  217. end;
  218.  
  219. function Factor : Complex;
  220. var
  221.   z, z1 : Complex;
  222.   f : Boolean;
  223. begin
  224.   z := Atom;
  225.   repeat
  226.     Skip;
  227.     f := True;
  228.     case Input^ of
  229.       '^' : begin
  230.               Get (Input);
  231.               z1 := Atom;
  232.               if z <> 0 then
  233.                 z := exp (z1 * ln (z))
  234.               else if z1 = 0 then
  235.                 z := 1
  236.             end;
  237.       otherwise f := False
  238.     end
  239.   until not f;
  240.   Factor := z
  241. end;
  242.  
  243. function Expr1 : Complex;
  244. var
  245.   z : Complex;
  246.   f : Boolean;
  247. begin
  248.   z := Factor;
  249.   repeat
  250.     Skip;
  251.     f := True;
  252.     case LoCase (Input^) of
  253.       '*' : begin
  254.               Get (Input);
  255.               z := z * Factor
  256.             end;
  257.       '/' : begin
  258.               Get (Input);
  259.               z := z / Factor
  260.             end;
  261.       '(', 'a' .. 'z' : z := z * Factor;
  262.       otherwise f := False
  263.     end
  264.   until not f;
  265.   Expr1 := z
  266. end;
  267.  
  268. function Expr;
  269. var
  270.   z : Complex;
  271.   s, f : Boolean;
  272. begin
  273.   Skip;
  274.   s := False;
  275.   while Input^ in ['+', '-'] do
  276.     begin
  277.       if Input^ = '-' then s := not s;
  278.       Get (Input);
  279.       Skip
  280.     end;
  281.   z := Expr1;
  282.   if s then z := - z;
  283.   repeat
  284.     Skip;
  285.     f := True;
  286.     case Input^ of
  287.       '+' : begin
  288.               Get (Input);
  289.               z := z + Expr1
  290.             end;
  291.       '-' : begin
  292.               Get (Input);
  293.               z := z - Expr1
  294.             end;
  295.       otherwise f := False
  296.     end
  297.   until not f;
  298.   Expr := z
  299. end;
  300.  
  301. begin
  302.   Writeln ('Enter expressions consisting of');
  303.   Writeln ('- real numbers, using the `e'' notation,');
  304.   Writeln ('- the constants `e'', `pi'', `i'',');
  305.   Writeln ('- the operators `+'', `-'', `*'', `/'', `^'',');
  306.   Writeln ('- the functions `abs'', `sqrt'', `sin'', `cos'', `tan'', `arctan'', `exp'', `ln'',');
  307.   Writeln ('- parentheses.');
  308.   Writeln;
  309.   Writeln ('Note: Due to the `e'' notation, there is a problem with terms like `2e'' which');
  310.   Writeln ('will be interpreted as `2*10^...''. If you mean `2*e'', write so, or `2 e''.');
  311.   Writeln ('Expressions like `3e+4+5'' can be confusing, but are interpreted according to');
  312.   Writeln ('the `e'' notation (i.e., this expression equals 30005).');
  313.   Writeln;
  314.   Writeln ('Enter an empty line when finished.');
  315.   while not EOLn do
  316.     begin
  317.       Writeln (Complex2String (Expr));
  318.       if not EOLn then Writeln ('Superfluous characters after the expression');
  319.       99 : Readln
  320.     end
  321. end;begin foo(*@@fjf479.pas*)
  322. end.
  323.